package com.sinevil.tcpTrans.tcp;

import com.sinevil.tcpTrans.entity.json.BasicJson;
import com.sinevil.tcpTrans.entity.json.handlers.ServerSocketJsonHandle;
import com.sinevil.tcpTrans.entity.task.TaskQueue;
import com.sinevil.tcpTrans.exceptions.ConnectionLostException;
import com.sinevil.tcpTrans.utils.fileTrans.FileTranser;
import com.sinevil.tcpTrans.utils.log.ServerLogger;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.channels.*;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;

/**
 * @Classname TCPServerNode
 * @Description TODO
 * @Version 1.0.0
 * @Date 2025/1/5 16:00
 * @Created by sinevil
 */
public abstract class TCPServerNode extends TCPTransNode{
    protected ServerSocketChannel serverSocketChannel;
    private final ArrayList<SocketChannel> connectedClients = new ArrayList<>();

    /**
     * 创建一个TCP服务器节点
     * @param serverPort
     * @throws NoSuchAlgorithmException 当不支持MD5算法时抛出
     * @throws AlreadyBoundException 如果套接字已经被绑定
     * @throws UnsupportedAddressTypeException 如果不支持给定地址的类型
     * @throws ClosedChannelException 如果通道关闭
     * @throws IOException 如果发生其他I/O错误
     * @throws SecurityException 如果已安装安全管理器，并且它拒绝该操作
     */
    public TCPServerNode(int serverPort) throws NoSuchAlgorithmException, IOException {
        super();
        this.fileTranser = new FileTranser(null,this);
        try {
            this.serverSocketChannel = ServerSocketChannel.open();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        this.serverSocketChannel.bind(new InetSocketAddress(serverPort));

        try {
            this.serverSocketChannel.configureBlocking(false);
            this.selector = Selector.open();
            this.socketJsonHandle = new ServerSocketJsonHandle(this,this.fileTranser);
            serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
        } catch (ClosedChannelException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }


    }

    @Override
    public void start() {
        nodeThread = new Thread(() -> {
            try {
                while (true) {
                    // 阻塞等待就绪事件发生，这里可以设置超时时间等参数来避免一直阻塞，例如：selector.select(1000); 表示等待1秒
                    selector.select();
                    // 获取所有就绪的SelectionKey集合
                    Set<SelectionKey> selectedKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectedKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        try {
                            if (key.isAcceptable()) {
                                handleClientConnect(key);
                            } else if (key.isReadable()) {
                                // 处理可读事件
                                this.handleReadableEvent(key);
                            } else if (key.isWritable()) {
                                // 处理可写事件
                                handleWritableEvent(key);
                            }
                        }catch (SocketException e){
                            // 处理客户端强制断开（
                            SocketChannel sc = (SocketChannel) key.channel();
                            key.cancel();
                            ServerLogger.LOGGER.warn("客户端: {}  断开连接", sc.getRemoteAddress());
                        }catch (ConnectionLostException e) {
                            // 处理客户端正常断开（如close()）
                            handleClientNormalDisconnect(key);
                        }
                    }
                }
            } catch (ClosedSelectorException e) {
                ServerLogger.LOGGER.error("选择器关闭，服务器停止");
            } catch (Exception e) {
                ServerLogger.LOGGER.error("Server error: {}", e.getMessage(), e);
            } finally {
                closeServerResources(); // 清理服务端资源
            }
        });
        nodeThread.start();
    }

    @Override
    public void init() {

    }

    public void sendMessageToAll(BasicJson basicJson){

    }

    private void handleClientConnect(SelectionKey key) throws IOException {
        // 处理新连接请求
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
        // 通过accept()方法获取与新连接的客户端对应的SocketChannel
        SocketChannel clientSocketChannel = serverSocketChannel.accept();

        if (clientSocketChannel!= null) {
            clientSocketChannel.configureBlocking(false);
            // 注册新连接的SocketChannel到Selector，关注可读事件
            clientSocketChannel.register(selector, SelectionKey.OP_READ);
            writeTaskQueueMap.put(clientSocketChannel, new TaskQueue());
            this.connectedClients.add(clientSocketChannel);
            ServerLogger.LOGGER.info("client:{}  已连接到服务器", clientSocketChannel.getRemoteAddress());
        }
    }

    /**
     * 清理文件传输资源
     * @param sc
     */
    private void cleanupFileTransfers(SocketChannel sc) {
        // 移除未完成的上传/下载任务
        uploadFileInfoMap.values().removeIf(fti -> fti.getSocketChannel() == sc);
        downloadFileInfoMap.values().removeIf(fti -> fti.getSocketChannel() == sc);
    }

    // 新增：处理客户端强制断开（SocketException）
    private void handleClientForceDisconnect(SelectionKey key) throws IOException {
        SocketChannel sc = (SocketChannel) key.channel();
        ServerLogger.LOGGER.warn("Client force disconnect: {}", sc.getRemoteAddress());
        handleClientDisconnect(key); // 通用清理方法
    }

    // 新增：处理客户端正常断开（ConnectionLostException）
    private void handleClientNormalDisconnect(SelectionKey key) throws IOException {
        SocketChannel sc = (SocketChannel) key.channel();
        ServerLogger.LOGGER.info("Client normal disconnect: {}", sc.getRemoteAddress());
        handleClientDisconnect(key); // 通用清理方法
    }

    // 核心：通用客户端断开处理（注销+清理）
    private void handleClientDisconnect(SelectionKey key) throws IOException {
        SocketChannel sc = (SocketChannel) key.channel();

        // 1. 取消Selector注册
        key.cancel();

        // 2. 关闭通道（处理异常）
        try {
            if (sc.isOpen()) {
                sc.close();
            }
        } catch (IOException e) {
            ServerLogger.LOGGER.warn("Failed to close channel: {}", e.getMessage());
        }

        // 3. 清理任务队列
        writeTaskQueueMap.remove(sc);

        // 4. 移除连接列表
        connectedClients.remove(sc);

        // 5. 清理文件传输状态（可选）
        cleanupFileTransfers(sc);

        ServerLogger.LOGGER.debug("Client removed: {}", sc.getRemoteAddress());
    }

    /**
     * 关闭服务器资源
     */
    private void closeServerResources() {
        try {
            if (serverSocketChannel != null && serverSocketChannel.isOpen()) {
                serverSocketChannel.close();
            }
            if (selector != null && selector.isOpen()) {
                selector.close();
            }
        } catch (IOException e) {
            ServerLogger.LOGGER.error("Failed to close server resources: {}", e.getMessage());
        }
    }
}